﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Navigation;

using Microsoft.Phone.Controls;

using NavigationCoercion.Actions;

namespace NavigationCoercion.Patterns
{
    internal class NavigatedPattern : INavigatedPattern
    {
        private class NavigationEntry
        {
            public const string ANY_PAGE = "*";

            public NavigationEntry(Type pageType, bool isOptional)
            {
                this.Page = pageType == null ? ANY_PAGE : pageType.GetPossibleXamlPagePath();
                this.IsOptional = isOptional;
            }

            public string Page { get; private set; }
            public bool IsOptional { get; private set; }            
        }

        private readonly IList<NavigationEntry> _pages = new List<NavigationEntry>();
        private RemoveActionBase _removeAction;

        public NavigatedPattern(Type type)
        {
            this._pages.Add(new NavigationEntry(type, false));
        }

        public INavigatedPattern ThenTo<TPage>()
        {
            this._pages.Add(new NavigationEntry(typeof(TPage), false));

            return this;
        }

        public INavigatedPattern ThenOptionallyTo<TPage>()
        {
            this._pages.Add(new NavigationEntry(typeof(TPage), true));

            return this;
        }

        public INavigatedPattern ThenToAnyPage()
        {
            this._pages.Add(new NavigationEntry(null, false));

            return this;
        }

        public void RemoveEntriesFromBackStack(int count)
        {
            this._removeAction = new RemoveStaticCountAction(count);            
        }

        public void RemoveEntriesFromBackStackTill<TPage>()
        {
            this._removeAction = new RemoveTillPageAction(typeof(TPage));
        }

        internal bool TryApply(NavigationEventArgs e, PhoneApplicationFrame frame)
        {
            var currentPage = frame.CurrentSource.ToString();
            var backstack = frame.BackStack.ToList();
            var lastPagesWithCurrent = Enumerable.Repeat(currentPage, 1).Concat(backstack.Select(je => je.Source.ToString())).ToList();

            var patternIterator = this._pages.Reverse().GetEnumerator();
            
            foreach (var stackPage in lastPagesWithCurrent)
            {
                while (patternIterator.MoveNext())
                {
                    if (patternIterator.Current.Page != NavigationEntry.ANY_PAGE && !stackPage.StartsWith(patternIterator.Current.Page))
                    {
                        if (!patternIterator.Current.IsOptional)
                            return false;
                    }
                    else
                        break;
                }
            }

            while (patternIterator.MoveNext())
            {
                if (!patternIterator.Current.IsOptional)
                    return false;
            }

            this.PerformRemoval(frame);

            return true;
        }

        private void PerformRemoval(PhoneApplicationFrame frame)
        {
            this._removeAction.PerformRemoval(frame);
        }
    }
}